{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "92448b5a",
   "metadata": {},
   "source": [
    "# Simulation of production line with defects - Dataset creation and Inference"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6037882b",
   "metadata": {},
   "source": [
    "_This notebook is originally created by [@paularamos](https://github.com/paularamo) for CVPR-2022 Tutorial [How to get quick and performant model for your edge application. From data to application](https://paularamo.github.io/cvpr-2022/)_\n",
    "\n",
    "### Definitions\n",
    "\n",
    "[Anomalib](https://github.com/openvinotoolkit/anomalib): Anomalib is a deep learning library that aims to collect state-of-the-art anomaly detection algorithms for benchmarking on both public and private datasets. Anomalib provides several ready-to-use implementations of anomaly detection algorithms described in the recent literature, as well as a set of tools that facilitate the development and implementation of custom models. The library has a strong focus on image-based anomaly detection, where the goal of the algorithm is to identify anomalous images, or anomalous pixel regions within images in a dataset.\n",
    "\n",
    "[Dobot](https://en.dobot.cn/products/education/magician.html) The Magician is an education robot arm portable and capable to run various automation tasks. With an interface in C++ and python we can control the robot using this notebook. \n",
    "\n",
    "> NOTE: \n",
    "If you don't have the robot you can replace it by your custom problem. "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ecfdde70",
   "metadata": {},
   "source": [
    "### Use case\n",
    "\n",
    "Using the [Dobot Magician](https://www.dobot.cc/dobot-magician/product-overview.html) we could simulate a production line system. Imagine we have a cubes factory and they need to know when a defect piece appear in the process. We know very well what the aspect ratio of the normal cubes is. Defects are coming no often and we need to put those defect cubes out of the production line.\n",
    "\n",
    "<img src=\"https://user-images.githubusercontent.com/10940214/174126337-b344bbdc-6343-4d85-93e8-0cb1bf39a4e3.png\" alt=\"drawing\" style=\"width:400px;\"/>\n",
    "\n",
    "\n",
    "| Class | Yellow cube | Red cube | Green cube | Inferencing using Anomalib\n",
    "| --------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------ | --------------------------------------------------------------------------- | --------------------------------------------------------------------------- |\n",
    "| Normal | <img src=\"https://user-images.githubusercontent.com/10940214/174083561-38eec918-efc2-4ceb-99b1-bbb4c91396b2.jpg\" alt=\"drawing\" style=\"width:150px;\"/> | <img src=\"https://user-images.githubusercontent.com/10940214/174083638-85ff889c-6222-4428-9c7d-9ad62bd15afe.jpg\" alt=\"drawing\" style=\"width:150px;\"/> | <img src=\"https://user-images.githubusercontent.com/10940214/174083707-364177d4-373b-4891-96ce-3e5ea923e440.jpg\" alt=\"drawing\" style=\"width:150px;\"/> | <img src=\"https://user-images.githubusercontent.com/10940214/174129305-03d9b71c-dfd9-492f-b42e-01c5c24171cc.jpg\" alt=\"drawing\" style=\"width:150px;\"/> |\n",
    "| Abnormal | <img src=\"https://user-images.githubusercontent.com/10940214/174083805-df0a0b03-58c7-4ba8-af50-fd94d3a13e58.jpg\" alt=\"drawing\" style=\"width:150px;\"/> | <img src=\"https://user-images.githubusercontent.com/10940214/174083873-22699523-22b4-4a55-a3da-6520095af8af.jpg\" alt=\"drawing\" style=\"width:150px;\"/> | <img src=\"https://user-images.githubusercontent.com/10940214/174083944-38d5a6f4-f647-455b-ba4e-69482dfa3562.jpg\" alt=\"drawing\" style=\"width:150px;\"/> | <img src=\"https://user-images.githubusercontent.com/10940214/174129253-f7a567d0-84f7-4050-8065-f00ba8bb973d.jpg\" alt=\"drawing\" style=\"width:150px;\"/> | \n",
    "\n",
    "Using Anomalib we are expecting to see this result.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "dc20e36d",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Anomalib imports\n",
    "from __future__ import annotations\n",
    "\n",
    "import sys\n",
    "import tempfile\n",
    "import time  # time library\n",
    "import urllib.request\n",
    "import zipfile\n",
    "from datetime import datetime\n",
    "from pathlib import Path\n",
    "from threading import Thread\n",
    "\n",
    "# importing required libraries\n",
    "import cv2  # OpenCV library\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "from anomalib.deploy import OpenVINOInferencer"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9cd6da02",
   "metadata": {},
   "source": [
    "## Download dataset and Robot API/Driver"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "76dae73e",
   "metadata": {},
   "source": [
    "We should prepare the folder to save the dataset and the Dobot API and drivers"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "339a835a",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Current directory:  /home/ashwin/projects/anomalib/notebooks/500_use_cases/501_dobot\n",
      "Working directory:  /home/ashwin/projects/anomalib\n",
      "Dataset directory:  /home/ashwin/projects/anomalib/datasets/cubes\n",
      "Notebook directory:  /home/ashwin/projects/anomalib/notebooks/500_use_cases/501_dobot\n"
     ]
    }
   ],
   "source": [
    "def up(n: int, nth_dir: Path = Path.cwd()) -> Path:\n",
    "    while n != 0:\n",
    "        nth_dir = nth_dir.parent\n",
    "        n -= 1\n",
    "    return nth_dir\n",
    "\n",
    "\n",
    "# Prepare the path to save the new image and the anomalib results\n",
    "current_directory = Path.cwd()\n",
    "print(\"Current directory: \", current_directory)\n",
    "working_path = up(3, current_directory)  # looking for anomalib folder\n",
    "print(\"Working directory: \", working_path)\n",
    "dataset_path = working_path / \"datasets\" / \"cubes\"\n",
    "dataset_path = Path(dataset_path)\n",
    "print(\"Dataset directory: \", dataset_path)\n",
    "notebook_path = current_directory\n",
    "print(\"Notebook directory: \", notebook_path)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3c980c5b",
   "metadata": {},
   "source": [
    "We now need to download the Dobot API and cubes dataset captured via the Dobot Magician."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "acd6958e",
   "metadata": {},
   "outputs": [],
   "source": [
    "def download_and_extract_zip(url: str, path: str | Path | None = None) -> None:\n",
    "    \"\"\"Download and extract a zip file.\n",
    "\n",
    "    Args:\n",
    "        url (str): URL to the zip file.\n",
    "        path (str | Path | None, optional): Path to download and extract the zip\n",
    "            file. Defaults to None.\n",
    "    \"\"\"\n",
    "    path = Path(path) if path else Path.cwd()\n",
    "\n",
    "    with tempfile.NamedTemporaryFile(suffix=\".zip\", delete=False) as tmp:\n",
    "        urllib.request.urlretrieve(url, path / tmp.name)\n",
    "        with zipfile.ZipFile(tmp.name, \"r\") as zip_ref:\n",
    "            zip_ref.extractall(path=path)\n",
    "\n",
    "\n",
    "download_and_extract_zip(\n",
    "    url=\"https://github.com/openvinotoolkit/anomalib/releases/download/dobot/dobot_api.zip\",\n",
    "    path=notebook_path,\n",
    ")\n",
    "download_and_extract_zip(\n",
    "    url=\"https://github.com/openvinotoolkit/anomalib/releases/download/dobot/cubes.zip\",\n",
    "    path=str(working_path) + \"/datasets\",\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "52aa7c07",
   "metadata": {},
   "source": [
    "Note: If you are using the Dobot, don forget to move the dobot_api files to the notebook_path directly. "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ebd2ea39",
   "metadata": {},
   "source": [
    "### Helper funtions\n",
    "\n",
    "Here you will find funtions to create filenames, capture images, run the inference and read the confidence of the detection."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "78aa3bce",
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "def filename_fc(root: str, dataset_root: Path) -> str:\n",
    "    \"\"\"\n",
    "    Create the filename for new data(images)\n",
    "\n",
    "    Args:\n",
    "        root (Path): directory to save the new images in\n",
    "            acquisition mode (abnormal or normal)\n",
    "            dataset_path: Initial path to save new images and results\n",
    "\n",
    "    Returns:\n",
    "            str: captured image filename\n",
    "    \"\"\"\n",
    "    now = datetime.now()\n",
    "    print(root)\n",
    "\n",
    "    image_name = \"\"\n",
    "\n",
    "    if root == \"abnormal\":\n",
    "        # check if a directory exists\n",
    "        path = dataset_root / \"abnormal\"\n",
    "        # Create a new directory if it does not exist\n",
    "        path.mkdir(exist_ok=True, parents=True)\n",
    "        image_name = str(Path(f\"{path}\" \"/input_\" + str(now.strftime(\"%Y%m%d%H%M%S\")) + \".jpg\"))\n",
    "    elif root == \"normal\":\n",
    "        # check if a directory exists\n",
    "        path = dataset_root / \"normal\"\n",
    "        # Create a new directory if it does not exist\n",
    "        path.mkdir(exist_ok=True, parents=True)\n",
    "        image_name = str(Path(f\"{path}\" + \"/input_\" + str(now.strftime(\"%Y%m%d%H%M%S\")) + \".jpg\"))\n",
    "    print(image_name)\n",
    "    return image_name"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8c6c7eab",
   "metadata": {},
   "source": [
    "### Prepare the mode (acquisition or inference mode) and define the work directory"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "0af9abcb",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Acquisition mode\n",
    "acquisition = False  # True False\n",
    "source = 0  # number of the camera you want to use\n",
    "folder = \"abnormal\"  # normal or abnormal\n",
    "\n",
    "# If acquisition is False this notebook will work in inference mode\n",
    "if acquisition is False:\n",
    "    # If you are running inference check where the OpenVINO model is stored\n",
    "    CONFIG_PATH = notebook_path / \"cubes_config.yaml\"\n",
    "    openvino_model_path = notebook_path / \"openvino\" / \"model.bin\"\n",
    "    metadata_path = notebook_path / \"openvino\" / \"meta_data.json\"\n",
    "    print(\"OpenVINO model exist: \", openvino_model_path.exists())\n",
    "    print(\"OpenVINO path: \", openvino_model_path)\n",
    "    print(\"Metadata model exist: \", metadata_path.exists())\n",
    "    print(\"Metadata path: \", metadata_path)\n",
    "\n",
    "    inferencer = OpenVINOInferencer(\n",
    "        config=CONFIG_PATH,  # Pass the config file to the inferencer.\n",
    "        path=openvino_model_path,  # Path to the OpenVINO IR model.\n",
    "        meta_data_path=metadata_path,  # Path to the metadata file.\n",
    "        device=\"CPU\",  # We would like to run it on an Intel CPU.\n",
    "    )\n",
    "\n",
    "    if dataset_path.exists() is False:\n",
    "        print(\"Make sure you have the dataset in a proper folder or it i already created\")\n",
    "else:\n",
    "    dataset_path.mkdir(parents=True, exist_ok=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "43968a85",
   "metadata": {},
   "source": [
    "### Helper class for implementing multi-threading\n",
    "\n",
    "Using multi-threading we will open the video to auto-capture an image when the robot locates the cube in front of the camera."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "8c1ec34c",
   "metadata": {},
   "outputs": [],
   "source": [
    "class CameraStream:\n",
    "    \"\"\"Helper class for implementing multi-threading.\"\"\"\n",
    "\n",
    "    def __init__(self, stream_id: int = 0) -> None:\n",
    "        self.stream_id = stream_id\n",
    "\n",
    "        # opening video capture stream\n",
    "        self.video_capture = cv2.VideoCapture(self.stream_id)\n",
    "        if self.video_capture.isOpened() is False:\n",
    "            print(\"[Exiting]: Error accessing cam stream.\")\n",
    "            sys.exit(0)\n",
    "        fps_input_stream = int(self.video_capture.get(5))  # hardware fps\n",
    "        print(f\"FPS of input stream: {fps_input_stream}\")\n",
    "\n",
    "        # reading a single frame from vcap stream for initializing\n",
    "        self.grabbed, self.frame = self.video_capture.read()\n",
    "        if self.grabbed is False:\n",
    "            print(\"[Exiting] No more frames to read\")\n",
    "            sys.exit(0)\n",
    "        # self.stopped is initialized to False\n",
    "        self.stopped = True\n",
    "        # thread instantiation\n",
    "        self.thread = Thread(target=self.update, args=())\n",
    "        self.thread.daemon = True  # daemon threads run in background\n",
    "\n",
    "    def start(self) -> None:\n",
    "        \"\"\"Method to start thread.\"\"\"\n",
    "        self.stopped = False\n",
    "        self.thread.start()\n",
    "\n",
    "    def update(self) -> None:\n",
    "        \"\"\"Method passed to thread to read next available frame.\"\"\"\n",
    "        while True:\n",
    "            if self.stopped is True:\n",
    "                break\n",
    "            self.grabbed, self.frame = self.video_capture.read()\n",
    "            if self.grabbed is False:\n",
    "                print(\"[Exiting] No more frames to read\")\n",
    "                self.stopped = True\n",
    "                break\n",
    "        self.video_capture.release()\n",
    "\n",
    "    def read(self):\n",
    "        \"\"\"Method to return latest read frame.\"\"\"\n",
    "        return self.frame\n",
    "\n",
    "    def stop(self) -> None:\n",
    "        \"\"\"Method to stop reading frames.\"\"\"\n",
    "        self.stopped = True"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3f90a588",
   "metadata": {},
   "source": [
    "### Function to visualize the prediction"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "b3c89109",
   "metadata": {},
   "outputs": [],
   "source": [
    "def visualize(prediction):\n",
    "    \"\"\"Function for visuzaling the predictions in inference mode\"\"\"\n",
    "\n",
    "    # create figure\n",
    "    fig = plt.figure(figsize=(12, 10))\n",
    "\n",
    "    # setting values to rows and column variables\n",
    "    rows = 1\n",
    "    columns = 5\n",
    "\n",
    "    # Adds a subplot at the 1st position\n",
    "    fig.add_subplot(rows, columns, 1)\n",
    "\n",
    "    # showing image\n",
    "    plt.imshow(prediction.image)\n",
    "    plt.axis(\"off\")\n",
    "    plt.title(\"Original\")\n",
    "\n",
    "    # Adds a subplot at the 2nd position\n",
    "    fig.add_subplot(rows, columns, 2)\n",
    "\n",
    "    # showing image\n",
    "    plt.imshow(prediction.anomaly_map)\n",
    "    plt.axis(\"off\")\n",
    "    plt.title(\"Anomaly Map\")\n",
    "\n",
    "    # Adds a subplot at the 3rd position\n",
    "    fig.add_subplot(rows, columns, 3)\n",
    "\n",
    "    # showing image\n",
    "    plt.imshow(prediction.heat_map)\n",
    "    plt.axis(\"off\")\n",
    "    plt.title(\"Heat Map\")\n",
    "\n",
    "    # Adds a subplot at the 4th position\n",
    "    fig.add_subplot(rows, columns, 4)\n",
    "\n",
    "    # showing image\n",
    "    plt.imshow(prediction.pred_mask)\n",
    "    plt.axis(\"off\")\n",
    "    plt.title(\"Pred. Mask\")\n",
    "\n",
    "    # Adds a subplot at the 4th position\n",
    "    fig.add_subplot(rows, columns, 5)\n",
    "\n",
    "    # showing image\n",
    "    plt.imshow(prediction.segmentations)\n",
    "    plt.axis(\"off\")\n",
    "    plt.title(\"Result\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "62854abc",
   "metadata": {},
   "source": [
    "### Using a webcam or a USB camera for running the inference\n",
    "\n",
    "Connect and identify your US camera, we will use a a video player to embed the video in this notebook. \n",
    "\n",
    "> NOTE: \n",
    "If you don't have the robot you can replace it by your custom problem. See the comments below. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a63a5943",
   "metadata": {
    "scrolled": false
   },
   "outputs": [],
   "source": [
    "# Dobot/general imports\n",
    "# pylint: disable=wrong-import-order\n",
    "import DobotDllType as dType  # comment this line if you don't have the Dobot Magician\n",
    "\n",
    "CON_STR = {\n",
    "    dType.DobotConnect.DobotConnect_NoError: \"DobotConnect_NoError\",\n",
    "    dType.DobotConnect.DobotConnect_NotFound: \"DobotConnect_NotFound\",\n",
    "    dType.DobotConnect.DobotConnect_Occupied: \"DobotConnect_Occupied\",\n",
    "}\n",
    "\n",
    "# Load Dll and get the CDLL object\n",
    "api = dType.load()\n",
    "\n",
    "# Connect Dobot\n",
    "state = dType.ConnectDobot(api, \"\", 115200)[0]\n",
    "print(\"Connect status:\", CON_STR[state])\n",
    "\n",
    "use_popup = True  # True\n",
    "\n",
    "if state == dType.DobotConnect.DobotConnect_NoError:\n",
    "    Calibration__0__Run__1 = None\n",
    "    Calibration_X = None\n",
    "    Calibration_Y = None\n",
    "    Calibration_Z = None\n",
    "    Place_X = None\n",
    "    Place_Y = None\n",
    "    Place_Z = None\n",
    "    Anomaly_X = None\n",
    "    Anomaly_Y = None\n",
    "    Anomaly_Z = None\n",
    "    j = None\n",
    "    k = None\n",
    "    time_start = None\n",
    "\n",
    "    print(\n",
    "        \"[HOME] Restore to home position at first launch, please wait 30 seconds after turnning on the Dobot Magician.\"\n",
    "    )\n",
    "    print(\n",
    "        \"[BLOCKS] Place them besides the non-motor side of the conveyor belt,\"\n",
    "        \" the same side where the pick and place arm is.\"\n",
    "    )\n",
    "    print(\"[PLACING BLOCKS] Place the blocks by 3×3.\")\n",
    "    print(\"[CALIBRATION POINT] Looking from the back of Dobot, the top left block is the calibration point.\")\n",
    "    print(\"[CALIBRATION] Set the first variable to 0 to test the calibration point, then set 1 to start running.\")\n",
    "    print(\n",
    "        \"[DIRECTION] Standing behind Dobot Magician facing its front direction, X is front and back direction, \"\n",
    "        \"Y is left and right direction. \"\n",
    "    )\n",
    "    print(\"[CONNECTION] Motor of the conveyor belt connects to port Stepper1.\")\n",
    "\n",
    "    Calibration__0__Run__1 = 1\n",
    "    Calibration_X = 221.2288\n",
    "    Calibration_Y = -117.0036\n",
    "    Calibration_Z = -42.3512\n",
    "    Place_X = 23.7489  # 42.2995 #\n",
    "    Place_Y = -264.2602  # -264.6927 #\n",
    "    Place_Z = 18.0862  # 63.65 #\n",
    "    Anomaly_X = -112  # -84.287 #\n",
    "    Anomaly_Y = -170  # -170.454 #\n",
    "    Anomaly_Z = 90  # 61.5359 #\n",
    "    dType.SetEndEffectorParamsEx(api, 59.7, 0, 0, 1)\n",
    "    j = 0\n",
    "    k = 0\n",
    "    dType.SetPTPJointParamsEx(api, 400, 400, 400, 400, 400, 400, 400, 400, 1)\n",
    "    dType.SetPTPCommonParamsEx(api, 100, 100, 1)\n",
    "    dType.SetPTPJumpParamsEx(api, 40, 100, 1)\n",
    "    dType.SetPTPCmdEx(api, 0, Calibration_X, Calibration_Y, Calibration_Z, 0, 1)\n",
    "    dType.SetEndEffectorSuctionCupEx(api, 0, 1)\n",
    "    STEP_PER_CRICLE = 360.0 / 1.8 * 10.0 * 16.0\n",
    "    MM_PER_CRICLE = 3.1415926535898 * 36.0\n",
    "    vel = float(0) * STEP_PER_CRICLE / MM_PER_CRICLE\n",
    "    dType.SetEMotorEx(api, 1, 0, int(vel), 1)\n",
    "\n",
    "    if Calibration__0__Run__1:\n",
    "        for count in range(9):\n",
    "            # initializing and starting multi-threaded webcam input stream\n",
    "            cam_stream = CameraStream(stream_id=0)  # 0 id for main camera\n",
    "            cam_stream.start()\n",
    "\n",
    "            dType.SetPTPCmdEx(api, 0, (Calibration_X - j), (Calibration_Y - k), (Calibration_Z - 10), 0, 1)\n",
    "            dType.SetEndEffectorSuctionCupEx(api, 1, 1)\n",
    "            # dType.dSleep(150)\n",
    "            dType.SetPTPCmdEx(api, 0, (Place_X - 0), (Place_Y - 0), (Place_Z + 90), 0, 1)\n",
    "\n",
    "            # adding a delay for simulating video processing time\n",
    "            delay = 0.3  # delay value in seconds\n",
    "            time.sleep(delay)\n",
    "            # Capture a frame from the video player - start thread\n",
    "            frame = cam_stream.read()\n",
    "            if not acquisition:\n",
    "                frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)\n",
    "                # Get the inference results.\n",
    "                # INFERENCE WITH OPENVINO\n",
    "                predictions = inferencer.predict(image=frame)\n",
    "                print(predictions.pred_score)\n",
    "                if predictions.pred_score > 0.48:  # modify the threshold depending of your needs\n",
    "                    dType.SetPTPCmdEx(api, 0, Anomaly_X, Anomaly_Y, Anomaly_Z, 0, 1)  # define point for abnormalities\n",
    "                else:\n",
    "                    dType.SetPTPCmdEx(api, 0, Place_X, Place_Y, Place_Z, 0, 1)\n",
    "                # visualize(predictions)\n",
    "\n",
    "            if acquisition:\n",
    "                # create filename to next frame\n",
    "                filename = filename_fc(folder, dataset_path)\n",
    "                cv2.imwrite(filename, frame)\n",
    "                dType.SetPTPCmdEx(api, 0, Place_X, Place_Y, Place_Z, 0, 1)\n",
    "                # print(\"continue in the conveyor belt\")\n",
    "\n",
    "            dType.SetEndEffectorSuctionCupEx(api, 0, 1)\n",
    "            # dType.dSleep(150)\n",
    "            j = j + 25\n",
    "            if j == 75:\n",
    "                k = k + 25\n",
    "                j = 0\n",
    "            dType.SetPTPCmdEx(api, 7, 0, 0, 20, 0, 1)\n",
    "            time_start = dType.gettime()[0]\n",
    "            STEP_PER_CRICLE = 360.0 / 1.8 * 10.0 * 16.0\n",
    "            MM_PER_CRICLE = 3.1415926535898 * 36.0\n",
    "            vel = float(50) * STEP_PER_CRICLE / MM_PER_CRICLE\n",
    "            dType.SetEMotorEx(api, 1, 1, int(vel), 1)\n",
    "            filename = None\n",
    "            score = 0\n",
    "            while True:\n",
    "                if (dType.gettime()[0]) - time_start >= 0.5:  # Time over conveyor belt\n",
    "                    STEP_PER_CRICLE = 360.0 / 1.8 * 10.0 * 16.0\n",
    "                    MM_PER_CRICLE = 3.1415926535898 * 36.0\n",
    "                    vel = float(0) * STEP_PER_CRICLE / MM_PER_CRICLE\n",
    "                    dType.SetEMotorEx(api, 1, 0, int(vel), 1)\n",
    "                    break\n",
    "        dType.SetEndEffectorSuctionCupEx(api, 0, 1)\n",
    "        dType.SetPTPCmdEx(api, 0, Calibration_X, Calibration_Y, Calibration_Z, 0, 1)\n",
    "        cam_stream.stop()  # stop the webcam stream"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5b1bb666",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "project_anomalib",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.16"
  },
  "vscode": {
   "interpreter": {
    "hash": "18f8999b3d132acda9ed72c7f0f7e54d3c533278cffbadac58c30769cf876377"
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
